import json
import os
import re
import random
import logging
from datetime import datetime
from typing import List, Dict, Any
from langchain_chroma import Chroma
from langchain_community.embeddings.dashscope import DashScopeEmbeddings
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
import asyncio
from pydantic import BaseModel, Field

# 加载环境变量
load_dotenv()

# 设置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


class InterviewState(BaseModel):
    position: str = "Python开发工程师"
    self_intro: str = None
    experience_years: int = 1
    projects: List[Dict] = Field(default_factory=list)
    skills: List[str] = Field(default_factory=list)
    questions: List[Dict] = Field(default_factory=list)
    answers: List[str] = Field(default_factory=list)
    evaluations: List[Dict] = Field(default_factory=list)
    start_time: datetime = Field(default_factory=datetime.now)
    end_time: datetime = None
    current_phase: str = "self_introduction"  # self_introduction, project_details, technical_assessment, conclusion


class InterviewAgent:
    def __init__(self):
        # 初始化嵌入模型
        self.embeddings = DashScopeEmbeddings(
            model='text-embedding-v1',
            dashscope_api_key=os.getenv("DASHSCOPE_API_KEY")
        )
        DB_PATH = os.path.join(os.path.dirname(__file__), "career_qa_db")
        # 初始化向量数据库（自动创建目录）
        os.makedirs(DB_PATH, exist_ok=True)
        self.db = Chroma(
            persist_directory=DB_PATH,
            embedding_function=self.embeddings
        )
        self.retriever = self.db.as_retriever(search_kwargs={"k": 20})

        # 初始化LLM（兼容阿里云DashScope）
        self.llm = ChatOpenAI(
            api_key=os.getenv('DASHSCOPE_API_KEY'),
            base_url='https://dashscope.aliyuncs.com/compatible-mode/v1',
            model_name="qwen-turbo",
            temperature=0.3
        )

        # 面试状态
        self.interview_state = None

    async def analyze_self_intro(self, self_intro: str) -> Dict:
        """深入分析自我介绍"""
        try:
            prompt = f"""
            请深入分析以下自我介绍，提取关键信息，直接返回JSON（不要多余文字）：
            {{
                "position": "精确职位名称",
                "skills": ["技能1", "技能2"],
                "projects": [{{
                    "name": "项目名称",
                    "company": "公司名称",
                    "role": "担任角色",
                    "technologies": ["技术1", "技术2"],
                    "responsibilities": "具体职责",
                    "achievements": "主要成就"
                }}],
                "experience_years": 工作经验年数,
                "industry": "行业领域"
            }}

            自我介绍内容：
            {self_intro}
            """

            result = await self.llm.ainvoke([
                ("system", "你是一位资深HR，需要从自我介绍中精确提取候选人信息，仅返回JSON"),
                ("human", prompt)
            ])

            # 清理返回内容
            json_str = re.search(r'\{.*\}', result.content, re.DOTALL).group()
            data = json.loads(json_str)

            # 确保projects是列表格式
            projects = data.get("projects", [])
            if isinstance(projects, dict):
                projects = [projects]

            return {
                "position": data.get("position", "Python开发工程师"),
                "skills": data.get("skills", []),
                "projects": projects,
                "experience_years": data.get("experience_years", 1),
                "industry": data.get("industry", "互联网")
            }
        except Exception as e:
            logger.error(f"自我介绍分析失败: {str(e)}")
            return {
                "position": "Python开发工程师",
                "skills": [],
                "projects": [],
                "experience_years": 1,
                "industry": "互联网"
            }

    async def generate_project_questions(self, project: Dict) -> List[Dict]:
        """生成针对特定项目的深入问题"""
        try:
            prompt = f"""
            根据以下项目经历生成3-5个深入的技术问题，返回JSON数组（不要多余文字）：
            [
                {{
                    "question": "问题内容",
                    "type": "project",
                    "difficulty": 难度值(1-5),
                    "focus_area": "问题关注领域"
                }}
            ]

            项目名称：{project.get('name', '未命名项目')}
            公司：{project.get('company', '未知公司')}
            角色：{project.get('role', '未指定')}
            使用技术：{', '.join(project.get('technologies', []))}
            职责：{project.get('responsibilities', '无')}
            成就：{project.get('achievements', '无')}

            要求：
            1. 问题要针对具体技术实现和解决方案
            2. 包含架构设计、技术选型、问题解决等方面
            3. 根据项目复杂度调整问题难度
            """

            result = await self.llm.ainvoke([
                ("system", "生成针对项目经历的技术问题，要求深入具体，仅返回JSON数组"),
                ("human", prompt)
            ])

            json_str = re.search(r'\[.*\]', result.content, re.DOTALL).group()
            questions = json.loads(json_str)

            # 添加项目上下文信息
            for q in questions:
                q["reference"] = f"关于{project['name']}项目({project.get('company', '')})"

            return questions

        except Exception as e:
            logger.error(f"项目问题生成失败: {str(e)}")
            return []

    async def generate_industry_questions(self, industry: str, position: str) -> List[Dict]:
        """生成行业相关问题"""
        try:
            prompt = f"""
            针对{industry}行业的{position}职位，生成3个专业问题，返回JSON数组：
            [
                {{
                    "question": "问题内容",
                    "type": "industry",
                    "difficulty": 难度值(3-5),
                    "focus_area": "问题关注领域"
                }}
            ]

            要求：
            1. 问题要体现行业特性和职位要求
            2. 包含行业最佳实践和常见挑战
            3. 根据职位资深程度调整问题难度
            """

            result = await self.llm.ainvoke([
                ("system", "生成行业特定的专业问题，仅返回JSON数组"),
                ("human", prompt)
            ])

            json_str = re.search(r'\[.*\]', result.content, re.DOTALL).group()
            questions = json.loads(json_str)

            for q in questions:
                q["reference"] = f"{industry}行业特定问题"

            return questions

        except Exception as e:
            logger.error(f"行业问题生成失败: {str(e)}")
            return []

    async def retrieve_technical_questions(self, position: str, experience_years: int) -> List[Dict]:
        """从向量库检索技术问题"""
        try:
            # 根据经验年数调整问题难度
            difficulty_level = min(5, max(1, round(experience_years)))

            query = f"{position} 面试题 {difficulty_level}年经验"
            docs = self.retriever.get_relevant_documents(query)

            questions = []
            for doc in docs[:10]:  # 取前10个相关文档
                content = doc.page_content
                # 从文档内容中提取问题
                match = re.search(r'问题[:：](.+?)(?:\n|$)', content)
                if match:
                    question = match.group(1).strip()
                    questions.append({
                        "question": question,
                        "type": "technical",
                        "difficulty": difficulty_level,
                        "reference": "常见技术面试题"
                    })

            # 去重并随机选择5个问题
            unique_questions = []
            seen = set()
            for q in questions:
                if q["question"] not in seen:
                    seen.add(q["question"])
                    unique_questions.append(q)

            return random.sample(unique_questions, min(5, len(unique_questions)))

        except Exception as e:
            logger.error(f"检索技术问题失败: {str(e)}")
            return []

    async def start_interview(self, self_intro: str) -> Dict:
        """启动面试流程"""
        try:
            # 分析自我介绍
            analysis = await self.analyze_self_intro(self_intro)

            # 初始化面试状态
            self.interview_state = InterviewState(
                position=analysis["position"],
                self_intro=self_intro,
                experience_years=analysis["experience_years"],
                projects=analysis["projects"],
                skills=analysis["skills"]
            )

            # 生成问题池（但不立即使用）
            all_questions = []

            # 1. 项目相关问题（每个项目3-5个问题）
            for project in analysis["projects"][:2]:  # 最多分析2个项目
                project_questions = await self.generate_project_questions(project)
                all_questions.extend(project_questions)

            # 2. 行业相关问题
            industry_questions = await self.generate_industry_questions(
                analysis.get("industry", "互联网"),
                analysis["position"]
            )
            all_questions.extend(industry_questions)

            # 3. 技术问题（从向量库检索）
            technical_questions = await self.retrieve_technical_questions(
                analysis["position"],
                analysis["experience_years"]
            )
            all_questions.extend(technical_questions)

            # 确保有问题可问
            if not all_questions:
                all_questions = [{
                    "question": "请介绍你最熟悉的Python框架及其使用场景",
                    "type": "basic",
                    "difficulty": 3,
                    "reference": ""
                }]

            # 将问题存入状态
            self.interview_state.questions = all_questions

            # 准备第一个问题（从项目问题开始）
            first_question = next(
                (q for q in all_questions if q["type"] == "project"),
                all_questions[0]
            )

            return {
                "status": "started",
                "position": analysis["position"],
                "experience_years": analysis["experience_years"],
                "first_question": first_question["question"],
                "total_questions": len(all_questions),
                "current_phase": "project_details"
            }

        except Exception as e:
            logger.error(f"启动面试失败: {str(e)}")
            raise ValueError("面试初始化失败，请检查自我介绍内容")

    async def evaluate_answer(self, question: Dict, answer: str) -> Dict:
        """严格评估回答"""
        try:
            prompt = f"""
            作为资深技术面试官，请严格评估以下回答，返回JSON：
            {{
                "technical_accuracy": 技术准确性(0-5),
                "depth_of_knowledge": 知识深度(0-5),
                "problem_solving": 问题解决能力(0-5),
                "communication": 表达清晰度(0-5),
                "practical_experience": 实践经验体现(0-5),
                "strengths": ["回答中的优点"],
                "weaknesses": ["具体不足之处"],
                "suggestions": ["针对性改进建议"],
                "overall_score": 综合评分(0-10),
                "skill_assessment": "初级/中级/高级"
            }}

            问题：{question['question']}
            问题类型：{question['type']}
            难度：{question.get('difficulty', 3)}/5
            期望考察点：{question.get('reference', '无')}

            候选人回答：
            {answer}

            评估要求：
            1. 根据问题类型和难度严格评分
            2. 对技术细节要特别关注
            3. 指出具体不足和改进建议
            4. 评估要客观专业
            
            输出要求：不要特殊符号
            """

            result = await self.llm.ainvoke([
                ("system", "你是严格的技术面试官，对回答进行专业评估，仅返回JSON"),
                ("human", prompt)
            ])

            json_str = re.search(r'\{.*\}', result.content, re.DOTALL).group()
            evaluation = json.loads(json_str)

            return {
                "question": question["question"],
                "question_type": question["type"],
                "question_difficulty": question.get("difficulty", 3),
                "answer": answer,
                "evaluation": evaluation,
                "timestamp": datetime.now().isoformat()
            }
        except Exception as e:
            logger.error(f"评估失败: {str(e)}")
            return {
                "question": question["question"],
                "answer": answer,
                "evaluation": {
                    "technical_accuracy": 0,
                    "depth_of_knowledge": 0,
                    "problem_solving": 0,
                    "communication": 0,
                    "practical_experience": 0,
                    "strengths": [],
                    "weaknesses": ["无法评估"],
                    "suggestions": ["请提供更详细的回答"],
                    "overall_score": 0,
                    "skill_assessment": "初级"
                }
            }

    async def submit_answer(self, answer: str) -> Dict:
        """提交回答并获取下一步"""
        if not self.interview_state:
            return {"status": "error", "message": "面试未初始化"}

        # 记录回答
        clean_answer = re.sub(r'\s+', ' ', answer).strip()
        if not clean_answer or clean_answer.lower() in ("不知道", "不清楚", "不了解"):
            clean_answer = "（未提供有效回答）"

        current_idx = len(self.interview_state.answers)
        self.interview_state.answers.append(clean_answer)

        # 评估回答
        evaluation = await self.evaluate_answer(
            self.interview_state.questions[current_idx],
            clean_answer
        )
        self.interview_state.evaluations.append(evaluation)

        # 检查是否结束
        if len(self.interview_state.answers) >= len(self.interview_state.questions):
            self.interview_state.end_time = datetime.now()
            self.interview_state.current_phase = "conclusion"
            report = await self.generate_report()
            return {
                "status": "completed",
                "report": report,
                "position": self.interview_state.position
            }

        # 获取下一个问题
        next_idx = len(self.interview_state.answers)
        next_question = self.interview_state.questions[next_idx]

        # 更新面试阶段
        if next_idx > len(self.interview_state.questions) * 0.7:  # 70%问题后进入技术评估
            self.interview_state.current_phase = "technical_assessment"

        return {
            "status": "next_question",
            "question": next_question["question"],
            "progress": f"{next_idx + 1}/{len(self.interview_state.questions)}",
            "question_type": next_question["type"],
            "current_phase": self.interview_state.current_phase
        }

    async def generate_report(self) -> Dict:
        """生成详细评估报告"""
        try:
            # 计算各项平均分
            evaluations = [e["evaluation"] for e in self.interview_state.evaluations]

            avg_scores = {
                "technical_accuracy": round(sum(e["technical_accuracy"] for e in evaluations) / len(evaluations), 2),
                "depth_of_knowledge": round(sum(e["depth_of_knowledge"] for e in evaluations) / len(evaluations), 2),
                "problem_solving": round(sum(e["problem_solving"] for e in evaluations) / len(evaluations), 2),
                "communication": round(sum(e["communication"] for e in evaluations) / len(evaluations), 2),
                "practical_experience": round(sum(e["practical_experience"] for e in evaluations) / len(evaluations),
                                              2),
                "overall_score": round(sum(e["overall_score"] for e in evaluations) / len(evaluations), 2)
            }

            # 收集所有优缺点
            all_strengths = []
            all_weaknesses = []
            for eval_item in evaluations:
                all_strengths.extend(eval_item.get("strengths", []))
                all_weaknesses.extend(eval_item.get("weaknesses", []))

            # 按出现频率排序
            common_strengths = sorted(
                list(set(all_strengths)),
                key=lambda x: all_strengths.count(x),
                reverse=True
            )[:3]  # 取前3个优势

            common_weaknesses = sorted(
                list(set(all_weaknesses)),
                key=lambda x: all_weaknesses.count(x),
                reverse=True
            )[:5]  # 取前5个弱点

            # 按问题类型分析表现
            type_performance = {}
            for q_type in ["project", "industry", "technical"]:
                type_evals = [e for e in self.interview_state.evaluations
                              if e.get("question_type") == q_type]
                if type_evals:
                    type_scores = [e["evaluation"] for e in type_evals]
                    type_performance[q_type] = {
                        "count": len(type_evals),
                        "avg_technical": round(sum(s["technical_accuracy"] for s in type_scores) / len(type_scores), 2),
                        "avg_problem_solving": round(sum(s["problem_solving"] for s in type_scores) / len(type_scores),
                                                     2)
                    }

            # 生成详细报告
            prompt = f"""
            候选人面试评估报告 - {self.interview_state.position}

            基本信息：
            - 职位：{self.interview_state.position}
            - 工作经验：{self.interview_state.experience_years}年
            - 面试时长：{(self.interview_state.end_time - self.interview_state.start_time).seconds // 60}分钟
            - 回答问题数：{len(self.interview_state.questions)}

            综合能力评估（满分5分）：
            - 技术准确性：{avg_scores['technical_accuracy']:.1f}
            - 知识深度：{avg_scores['depth_of_knowledge']:.1f}
            - 问题解决能力：{avg_scores['problem_solving']:.1f}
            - 表达清晰度：{avg_scores['communication']:.1f}
            - 实践经验：{avg_scores['practical_experience']:.1f}
            - 综合评分：{avg_scores['overall_score']:.1f}/10

            主要优势：
            {chr(10).join(f"- {s}" for s in common_strengths) or "无突出优势"}

            需要改进的领域：
            {chr(10).join(f"- {w}" for w in common_weaknesses) or "无显著缺点"}

            按问题类型表现：
            {json.dumps(type_performance, indent=4, ensure_ascii=False)}

            请生成包含以下部分的专业评估报告：
            1. 综合能力评价（300字）
            2. 技术能力详细分析（按领域）
            3. 3个最具代表性的问题与回答分析
            4. 具体改进建议（针对每个弱点）
            5. 是否推荐录用及理由
            6. 最终技能等级评估（初级/中级/高级）

            要求：
            - 使用专业、客观的语言
            - 指出具体的技术不足
            - 提供可操作的改进建议
            - 评估要严格但公正
            
            输出要求：不要特殊符号
            """

            result = await self.llm.ainvoke([
                ("system", "你是技术总监，生成专业、严格的面试评估报告，使用Markdown格式"),
                ("human", prompt)
            ])

            return {
                "summary": {
                    "position": self.interview_state.position,
                    "experience_years": self.interview_state.experience_years,
                    "avg_scores": avg_scores,
                    "strengths": common_strengths,
                    "weaknesses": common_weaknesses,
                    "skill_level": max(
                        set(e["evaluation"]["skill_assessment"] for e in self.interview_state.evaluations),
                        key=lambda x: [e["evaluation"]["skill_assessment"] for e in
                                       self.interview_state.evaluations].count(x)
                    )
                },
                "detailed_report": result.content,
                "question_analysis": [
                    {
                        "question": e["question"],
                        "answer": e["answer"][:200] + "..." if len(e["answer"]) > 200 else e["answer"],
                        "evaluation": {
                            "score": e["evaluation"]["overall_score"],
                            "strengths": e["evaluation"].get("strengths", [])[:2],
                            "weaknesses": e["evaluation"].get("weaknesses", [])[:2]
                        }
                    }
                    for e in sorted(
                        self.interview_state.evaluations,
                        key=lambda x: x["question_difficulty"],
                        reverse=True
                    )[:3]  # 取难度最高的3个问题
                ]
            }

        except Exception as e:
            logger.error(f"报告生成失败: {str(e)}")
            return {
                "error": "无法生成完整报告",
                "summary": {
                    "avg_scores": {"overall_score": 0},
                },
                "detailed_report": "报告生成失败"
            }


async def async_input(prompt: str) -> str:
    """异步获取用户输入"""
    return await asyncio.get_event_loop().run_in_executor(None, input, prompt)


async def main():
    print("=== 模拟技术面试 ===")
    print("请提供您的自我介绍（包含职位、技术栈、项目经验等信息）")
    print("示例：")
    print(
        "我叫张三，拥有3年Python后端开发经验，在上一家公司主要负责AI模拟面试系统和智能问答系统的开发，使用技术包括Django、Flask、Python、MySQL等。\n")

    try:
        agent = InterviewAgent()

        # 获取自我介绍
        while True:
            self_intro = await async_input("请输入您的自我介绍（输入quit退出）:\n")
            if self_intro.lower() == 'quit':
                return

            if self_intro.strip():
                break
            print("自我介绍不能为空，请重新输入\n")

        # 开始面试
        print("\n分析您的资历并准备问题...")
        start_result = await agent.start_interview(self_intro)

        print(f"\n=== {start_result['position']} 技术面试开始 ===")
        print(f"工作经验: {start_result['experience_years']}年")
        print(f"共 {start_result['total_questions']} 个问题")
        print(f"\n首先，请回答关于您项目经验的问题：")
        print(f"\n问题 1/{start_result['total_questions']}: {start_result['first_question']}")

        # 问答循环
        while True:
            answer = await async_input("\n您的回答: ")
            result = await agent.submit_answer(answer)

            if result["status"] == "completed":
                print("\n=== 面试结束 ===\n")
                print(f"职位: {result['position']}")
                print("\n=== 技术评估报告 ===\n")

                # 打印摘要
                print("[能力摘要]")
                print(f"综合评分: {result['report']['summary']['avg_scores']['overall_score']:.1f}/10")
                print(f"技术准确性: {result['report']['summary']['avg_scores']['technical_accuracy']:.1f}/5")
                print(f"问题解决能力: {result['report']['summary']['avg_scores']['problem_solving']:.1f}/5")
                print(f"\n技能等级评估: {result['report']['summary']['skill_level']}")

                # 打印详细报告
                print("\n[详细评估]")
                print(result["report"]["detailed_report"])

                # 打印问题分析
                print("\n[关键问题分析]")
                for i, qa in enumerate(result["report"]["question_analysis"], 1):
                    print(f"\n问题{i} (评分: {qa['evaluation']['score']}/10):")
                    print(f"问题: {qa['question']}")
                    print(f"回答: {qa['answer']}")
                    print(f"优点: {', '.join(qa['evaluation']['strengths']) or '无'}")
                    print(f"不足: {', '.join(qa['evaluation']['weaknesses']) or '无'}")

                break

            elif result["status"] == "next_question":
                # 根据面试阶段提示
                if result["current_phase"] == "project_details":
                    phase_note = "（项目细节追问）"
                elif result["current_phase"] == "technical_assessment":
                    phase_note = "（技术能力评估）"
                else:
                    phase_note = ""

                print(f"\n问题 {result['progress']}{phase_note}: {result['question']}")
                if result["question_type"] == "project":
                    print("（请详细描述您的项目经验和技术实现）")

            else:
                print(f"\n错误: {result.get('message', '未知错误')}")
                break

    except Exception as e:
        print(f"\n面试异常终止: {str(e)}")
    finally:
        print("\n感谢参与本次技术面试！")


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except RuntimeError as e:
        if "Event loop is closed" not in str(e):
            raise